package fr.cephb.operon.server.ws;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import fr.cephb.joperon.core.Operon;
import fr.cephb.joperon.core.bio.Assembly;
import fr.cephb.joperon.core.bio.Chromosome;
import fr.cephb.joperon.core.db.SnpMapDB;
import fr.cephb.joperon.core.entities.SnpIds;
import fr.cephb.joperon.core.entities.SnpMap;
import fr.cephb.joperon.core.entities.SnpSeq;
import fr.cephb.joperon.tool.OperonFactory;

public class BasicSnpTool
	implements SnpTool
	{
	private Assembly assembly=Assembly.getDefaultAssembly();
	private File berkeleyDBDir=null;
	private int limitSnpCount=10000;
	
	
	/**
	 * Empty constructor
	 */
	protected BasicSnpTool()
		{
		}
	
	
	public void setLimitSnpCount(int limitSnpCount) {
		this.limitSnpCount = limitSnpCount;
		}
	
	protected Assembly getAssembly() {
		return assembly;
		}
	
	public void setAssembly(Assembly assembly) {
		this.assembly = assembly;
		}
	
	public void setBerkeleyDBDir(File berkeleyDBDir) {
		this.berkeleyDBDir = berkeleyDBDir;
		}
	
	protected File getBerkeleyDBDir()
		{
		if(this.berkeleyDBDir==null)
			{
			String s= Operon.guessBerkeleyDBHome();
			if(s==null) throw new IllegalStateException("BekreleyDB home was not set");
			this.berkeleyDBDir= new File(s);
			}
		return berkeleyDBDir;
		}
	
	@Override
	public
		SNP[] getSNPByName(String rsName) throws Exception
		{
		if(rsName==null) return new SNP[0];
		List<SNP> list= new ArrayList<SNP>();
		Operon operon=null;
		OperonFactory factory= null;
		try {
			operon= Operon.newInstance(getBerkeleyDBDir());
			factory= new OperonFactory(operon);
			for(SnpIds snpid:factory.getSnpIds().get(rsName.toLowerCase()))
				{
				SNP mysnp= new SNP();
				SnpMap map=factory.getSnpMap(getAssembly()).get(snpid.getFid());
				
				
				mysnp.setName(rsName);
				mysnp.setAcn(map.getAcn());
				mysnp.setChromosome(map.getChromosome().toString());
				mysnp.setPosition(map.getPosition());
				
				SnpSeq snpseq= factory.getSnpSeq(getAssembly()).get(map.getFid());
    			if(snpseq!=null)
    				{
    				mysnp.setSequence(snpseq.asFastaSequence());
    				}
				
				list.add(mysnp);
				}
			} 
		catch (Exception e)
			{
			e.printStackTrace();
			throw e;
			}
		finally
			{
			if(factory!=null) factory.close();
			if(operon!=null) operon.safeClose();
			}
		return list.toArray(new SNP[list.size()]);
		}
	
	
	@Override
	public String getAssemblyName() throws Exception {
		return getAssembly().getName();
		}
	
	@Override
	public SNP[] getSNPByPosition(String krom, int start, int end)
		throws Exception
		{
		Chromosome chrom= Chromosome.getByName(krom);
		if(chrom==null || chrom==Chromosome.ChrUndefined ) throw new IllegalArgumentException("bad chromosome");
		if(start>end) return new SNP[0];
		List<SNP> list= new ArrayList<SNP>();
		
		Operon operon=null;
		OperonFactory factory= null;
		SnpMapDB.ValueIterator iter=null;
		try {
			int snpIndex=0;
			operon= Operon.newInstance(getBerkeleyDBDir());
			factory= new OperonFactory(operon);
			iter=factory.getSnpMap(getAssembly()).listBetween(chrom, start, end);
			while(iter.hasNext())
				{
				SnpMap map= iter.next();
				
				
				if(!map.getAcn().matches("rs[0-9]+")) continue;
    			
    			if(this.limitSnpCount<=snpIndex)
    				{
    				throw new IllegalArgumentException("Ouput limited to "+this.limitSnpCount+" entries");
    				}
    			snpIndex++;
				
				SNP mysnp= new SNP();
				mysnp.setName(map.getAcn());
				mysnp.setAcn(map.getAcn());
				mysnp.setChromosome(map.getChromosome().toString());
				mysnp.setPosition(map.getPosition());
				
				SnpSeq snpseq= factory.getSnpSeq(getAssembly()).get(map.getFid());
    			if(snpseq!=null)
    				{
    				mysnp.setSequence(snpseq.asFastaSequence());
    				}
				
				list.add(mysnp);
				}
			} 
		catch (Exception e)
			{
			e.printStackTrace();
			throw e;
			}
		finally
			{
			if(factory!=null) factory.close();
			if(operon!=null) operon.safeClose();
			}
		return list.toArray(new SNP[list.size()]);
		}
	
	}
